﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ATest.Bll.Interfaces;
using ATest.Controllers;
using System.Web.Mvc;
using System.Web.Routing;
using ATest.Bll;

namespace ATest.Tests.ControllerTests
{
    [TestClass]
    public class TestControllerTest : BaseControllerTest
    {
        private List<MockObjects.MockTest> _TestData;
        private MockObjects.MockTestRepository _TestRepository;
        private TestController _Controller;

        protected override void Initalise()
        {
            _TestData = MockObjects.MockTest.CreateList(10);
            _TestRepository = new MockObjects.MockTestRepository(_TestData.Select(x => x.Object));
            _Controller = new TestController(_TestRepository.Object);

            ControllerContext controllerContext = new ControllerContext(_MockHttpContext.Object, new RouteData(), _Controller);
            _Controller.ControllerContext = controllerContext;
        }

        [TestMethod]
        public void IndexReturns_CorrectView()
        {
            var result = _Controller.Index();

            Assert.IsNotNull(result);
            Assert.IsInstanceOfType(result, typeof(ViewResult));

            var viewResult = (ViewResult)result;

            Assert.IsNotNull(viewResult.ViewData.Model);
            Assert.IsInstanceOfType(viewResult.ViewData.Model, typeof(List<Test>));

            var data = (List<Test>) viewResult.ViewData.Model;

            Assert.AreEqual(_TestData.Count, data.Count);
        }

        [TestMethod]
        public void IndexReturns_CorrectAjaxView()
        {
            _MockHttpRequest.SetAjax(true);

            var result = _Controller.Index();

            Assert.IsNotNull(result);
            Assert.IsInstanceOfType(result, typeof(PartialViewResult));

            var viewResult = (PartialViewResult)result;

            Assert.IsNotNull(viewResult.ViewData.Model);
            Assert.IsInstanceOfType(viewResult.ViewData.Model, typeof(List<Test>));

            var data = (List<Test>)viewResult.ViewData.Model;

            Assert.AreEqual(_TestData.Count, data.Count);
        }

        [TestMethod]
        public void Details_WithInvalidId_ThrowsNotFoundView()
        {
            var result = _Controller.Details(0) as ViewResult;

            Assert.IsNotNull(result);
            Assert.AreEqual("NotFound", result.ViewName);
        }

        [TestMethod]
        public void Details_WithValidId_ReturnsView()
        {
            var result = _Controller.Details(_TestData[1].Object.Id) as ViewResult;

            Assert.IsNotNull(result);
            Assert.IsNotNull(result.ViewData.Model);
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(Test));
            Assert.AreEqual(_TestData[1].Object, result.ViewData.Model);
        }

        [TestMethod]
        public void Details_WithValidIdAndAjaxRequest_ReturnsPartialView()
        {
            _MockHttpRequest.SetAjax(true);

            var result = _Controller.Details(_TestData[1].Object.Id) as PartialViewResult;

            Assert.IsNotNull(result);
            Assert.IsNotNull(result.ViewData.Model);
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(Test));
            Assert.AreEqual(_TestData[1].Object, result.ViewData.Model);
            Assert.AreEqual("Ajax_Details", result.ViewName);
        }

        [TestMethod]
        public void Edit_WithInvalidId_ThrowsNotFoundView()
        {
            var result = _Controller.Edit(0) as ViewResult;

            Assert.IsNotNull(result);
            Assert.AreEqual("NotFound", result.ViewName);
        }

        [TestMethod]
        public void Edit_WithValidId_ReturnsView()
        {
            var result = _Controller.Edit(_TestData[1].Object.Id) as ViewResult;

            Assert.IsNotNull(result);
            Assert.IsNotNull(result.ViewData.Model);
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(Test));
            Assert.AreEqual(_TestData[1].Object, result.ViewData.Model);
        }

        [TestMethod]
        public void Edit_WithValidIdAndAjaxRequest_ReturnsPartialView()
        {
            _MockHttpRequest.SetAjax(true);

            var result = _Controller.Edit(_TestData[1].Object.Id) as PartialViewResult;

            Assert.IsNotNull(result);
            Assert.IsNotNull(result.ViewData.Model);
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(Test));
            Assert.AreEqual(_TestData[1].Object, result.ViewData.Model);
            Assert.AreEqual("Ajax_Edit", result.ViewName);
        }

        [TestMethod]
        public void Create_ReturnsView()
        {

            var result = _Controller.Create() as ViewResult;

            Assert.IsNotNull(result);
            Assert.IsNull(result.ViewData.Model);

        }

        [TestMethod]
        public void Create_WithAjaxRequest_ReturnsPartialView()
        {
            _MockHttpRequest.SetAjax(true);

            var result = _Controller.Create() as PartialViewResult;

            Assert.IsNotNull(result);
            Assert.IsNull(result.ViewData.Model);

            Assert.AreEqual("Ajax_Create", result.ViewName);
        }

        [TestMethod]
        public void Edit_WithErrors_ReturnsView()
        {
            _TestRepository.Setup(x => x.SaveChanges()).Throws(new Bll.Errors.ValidationException());
            _TestData[0].Setup(x => x.IsValid).Returns(false);
            _TestData[0].Setup(x => x.GetRuleViolations()).Returns(new RuleViolation[]{new RuleViolation("Name cannot be null", "Name")});

            var result = _Controller.Edit(_TestData[0].Object.Id, null) as ViewResult;

            Assert.IsNotNull(result);
            Assert.AreEqual(1, result.ViewData.ModelState.Count());
            Assert.IsNotNull(result.ViewData.Model);
            Assert.AreEqual(_TestData[0].Object, result.ViewData.Model);

        }

        [TestMethod]
        public void Edit_WithErrorsAndAjax_ReturnsPartialView()
        {
            _MockHttpRequest.SetAjax(true);

            _TestRepository.Setup(x => x.SaveChanges()).Throws(new Bll.Errors.ValidationException());
            _TestData[0].Setup(x => x.IsValid).Returns(false);
            _TestData[0].Setup(x => x.GetRuleViolations()).Returns(new RuleViolation[] { new RuleViolation("Name cannot be null", "Name") });

            var result = _Controller.Edit(_TestData[0].Object.Id, null) as PartialViewResult;

            Assert.IsNotNull(result);
            Assert.AreEqual(1, result.ViewData.ModelState.Count());
            Assert.IsNotNull(result.ViewData.Model);
            Assert.AreEqual(_TestData[0].Object, result.ViewData.Model);

        }

        [TestMethod]
        public void Edit_WithNoErrors_ReturnsRedirectToAction()
        {

            var result = _Controller.Edit(_TestData[0].Object.Id, "Name") as RedirectToRouteResult;

            Assert.IsNotNull(result);
            Assert.AreEqual("Index", result.RouteValues["action"]);

            _TestRepository.Verify(x => x.SaveChanges(), Moq.Times.Once());

        }

        [TestMethod]
        public void Edit_WithNoErrorsAndAjax_ReturnsRedirectToAction()
        {
            _MockHttpRequest.SetAjax(true);

            var result = _Controller.Edit(_TestData[0].Object.Id, "Name") as PartialViewResult;

            Assert.IsNotNull(result);
            Assert.IsNotNull(result.ViewData.Model);
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(List<Test>));
            var data = (List<Test>)result.ViewData.Model;
            Assert.AreEqual(_TestData.Count, data.Count);

            _TestRepository.Verify(x => x.SaveChanges(), Moq.Times.Once());

        }

        [TestMethod]
        public void Create_WithErrors_ReturnsView()
        {
            _TestRepository.Setup(x => x.SaveChanges()).Throws(new Bll.Errors.ValidationException());
            _TestData[0].Setup(x => x.IsValid).Returns(false);
            _TestData[0].Setup(x => x.GetRuleViolations()).Returns(new RuleViolation[] { new RuleViolation("Name cannot be null", "Name") });

            var result = _Controller.Create(null) as ViewResult;

            Assert.IsNotNull(result);
            Assert.AreEqual(1, result.ViewData.ModelState.Count());
            Assert.IsNotNull(result.ViewData.Model);
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(Test));
            var data = (Test)result.ViewData.Model;
            Assert.AreEqual(0, data.Id);
        }

        [TestMethod]
        public void Create_WithErrorsAndAjax_ReturnsPartialView()
        {
            _MockHttpRequest.SetAjax(true);

            _TestRepository.Setup(x => x.SaveChanges()).Throws(new Bll.Errors.ValidationException());
            _TestData[0].Setup(x => x.IsValid).Returns(false);
            _TestData[0].Setup(x => x.GetRuleViolations()).Returns(new RuleViolation[] { new RuleViolation("Name cannot be null", "Name") });

            var result = _Controller.Create(null) as PartialViewResult;

            Assert.IsNotNull(result);
            Assert.AreEqual(1, result.ViewData.ModelState.Count());
            Assert.IsNotNull(result.ViewData.Model);

            Assert.IsInstanceOfType(result.ViewData.Model, typeof(Test));
            var data = (Test)result.ViewData.Model;
            Assert.AreEqual(0, data.Id);

        }

        [TestMethod]
        public void Create_WithNoErrors_ReturnsRedirectToAction()
        {

            var result = _Controller.Create("Name") as RedirectToRouteResult;

            Assert.IsNotNull(result);
            Assert.AreEqual("Index", result.RouteValues["action"]);

            _TestRepository.Verify(x => x.SaveChanges(), Moq.Times.Once());

        }

        [TestMethod]
        public void Create_WithNoErrorsAndAjax_ReturnsRedirectToAction()
        {
            _MockHttpRequest.SetAjax(true);

            var result = _Controller.Create("Name") as PartialViewResult;

            Assert.IsNotNull(result);
            Assert.IsNotNull(result.ViewData.Model);
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(List<Test>));
            var data = (List<Test>)result.ViewData.Model;
            Assert.AreEqual(_TestData.Count, data.Count);

            _TestRepository.Verify(x => x.SaveChanges(), Moq.Times.Once());

        }


    }
}
